package com.ruoyi.act.module.service.impl;

import com.github.pagehelper.PageInfo;
import com.ruoyi.act.module.domain.ActProcess;
import com.ruoyi.act.module.service.ITaskService;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class TaskServiceImpl implements ITaskService {

    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;

    private TaskQuery taskQuery;


    @Override
    public List<Map<String, Object>> findTaskList(ActProcess actProcess) {
        List<Map<String, Object>> mapList = new ArrayList<>();
        for (String s : actProcess.getAssignees()) {
            try {
                taskQuery = taskService.createTaskQuery();
                taskQuery.processDefinitionKey(actProcess.getProcessKey()).taskCandidateOrAssigned(s);
                List<Task> list = taskQuery.orderByTaskCreateTime().desc().list();
                list.forEach(info -> {
                    Map<String, Object> map = new HashMap<>();
                    map.put("id", info.getId());
                    map.put("assignee", info.getAssignee());
                    map.put("businessKey", info.getBusinessKey());
                    mapList.add(map);
                });
            } catch (Exception e) {
                continue;
            }
        }
        if (mapList.size() > 0) {
            return mapList;
        } else {
            return null;
        }

    }

    @Override
    public PageInfo findPage(ActProcess actProcess) {
        Integer pageNum = actProcess.getPageNum() == null ? 0 : actProcess.getPageNum() - 1;
        Integer pageSize = actProcess.getPageSize() == null ? 10 : actProcess.getPageSize();

        taskQuery = taskService.createTaskQuery();
        taskQuery.processDefinitionKey(actProcess.getProcessKey()).taskCandidateOrAssigned(actProcess.getTaskAssignee());
        List<Task> list = taskQuery.orderByTaskCreateTime().desc().listPage(pageNum * pageSize, pageSize);

        List<Map<String, Object>> mapList = new ArrayList<>();
        list.forEach(info -> {
            Map<String, Object> map = new HashMap<>();
            map.put("id", info.getId());
            map.put("name", info.getName());
            map.put("assignee", info.getAssignee() == null ? "" : info.getAssignee());
            map.put("businessKey", info.getBusinessKey());
            map.put("createTime", info.getCreateTime());
            mapList.add(map);
        });

        PageInfo pageInfo = PageInfo.of(mapList);
        pageInfo.setTotal(taskQuery.count());
        pageInfo.setPageNum(pageNum);
        pageInfo.setPageSize(pageSize);

        return pageInfo;
    }

    @Override
    public Task query(ActProcess actProcess) {
        taskQuery = taskService.createTaskQuery();
        if (StringUtils.isNotBlank(actProcess.getBusinessKey())) {
            taskQuery.processInstanceBusinessKey(actProcess.getBusinessKey());
        }

        taskQuery.processDefinitionKey(actProcess.getProcessKey()).taskCandidateOrAssigned(actProcess.getTaskAssignee());
        return taskQuery.singleResult();
    }

    @Override
    public List<Task> queryList(ActProcess actProcess) {
        taskQuery = taskService.createTaskQuery();
        taskQuery.processDefinitionKey(actProcess.getProcessKey()).taskCandidateOrAssigned(actProcess.getTaskAssignee());
        List<Task> list = taskQuery.orderByTaskCreateTime().desc().list();
        return list;
    }

    @Override
    public void complete(String taskId) {
        taskService.complete(taskId);
    }

    @Override
    public void complete(ActProcess actProcess) {
        claim(actProcess);
        taskService.complete(actProcess.getTaskId(), actProcess.getVariables(), true);
    }

    @Override
    public void claim(ActProcess actProcess) {
        taskQuery = taskService.createTaskQuery();
        taskQuery.taskId(actProcess.getTaskId()).taskCandidateUser(actProcess.getTaskAssignee());
        if (taskQuery.singleResult()!=null) {
            taskService.claim(actProcess.getTaskId(), actProcess.getTaskAssignee());
        }
    }

    @Override
    public void setAssignee(ActProcess actProcess) {
        taskQuery = taskService.createTaskQuery();
        taskQuery.taskId(actProcess.getTaskId()).taskAssignee(actProcess.getTaskAssignee());
        Task task = taskQuery.singleResult();
        if (task != null) {
            if (StringUtils.isNotBlank(task.getAssignee())) {
                // userId == null 表示 归还任务到组 有参数时表示 任务交接给该用户
                taskService.setAssignee(actProcess.getTaskId(), StringUtils.isBlank(actProcess.getUserId()) ? null : actProcess.getUserId());
            }
        }
    }

    @Override
    public boolean withdraw(ActProcess actProcess) {
        Task task = taskService.createTaskQuery()
                .processDefinitionKey(actProcess.getProcessKey())
                .processInstanceBusinessKey(actProcess.getBusinessKey())
                .singleResult();
        if (task != null) {

            List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                    .processInstanceBusinessKey(actProcess.getBusinessKey())
                    .taskAssignee(actProcess.getTaskAssignee()).orderByTaskCreateTime().desc()
                    .list();

            if (list.size() < 1) {
                return false;
            }
            //去除倒序第一条
            HistoricTaskInstance myTask = list.get(0);

            if (myTask != null) {
                String myTaskId = myTask.getId();
                String processDefinitionId = myTask.getProcessDefinitionId();
                BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);

                String myActivityId = null;
                List<HistoricActivityInstance> haiList = historyService.createHistoricActivityInstanceQuery()
                        .executionId(myTask.getExecutionId()).finished().list();
                for (HistoricActivityInstance hai : haiList) {
                    if (myTaskId.equals(hai.getTaskId())) {
                        myActivityId = hai.getActivityId();
                        break;
                    }
                }

                FlowNode myFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(myActivityId);
                Execution execution = runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
                String activityId = execution.getActivityId();
                FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityId);

                //记录原活动方向
                List<SequenceFlow> oriSequenceFlows = new ArrayList<>();
                oriSequenceFlows.addAll(flowNode.getOutgoingFlows());

                //清理活动方向
                flowNode.getOutgoingFlows().clear();
                //建立新方向
                List<SequenceFlow> newSequenceFlowList = new ArrayList<SequenceFlow>();
                SequenceFlow newSequenceFlow = new SequenceFlow();
                newSequenceFlow.setId(UUID.randomUUID().toString());
                newSequenceFlow.setSourceFlowElement(flowNode);
                newSequenceFlow.setTargetFlowElement(myFlowNode);
                newSequenceFlowList.add(newSequenceFlow);
                flowNode.setOutgoingFlows(newSequenceFlowList);

                // 记录
                Authentication.setAuthenticatedUserId(task.getAssignee());
                taskService.addComment(task.getId(), task.getProcessInstanceId(), "用户" + actProcess.getTaskAssignee() + "撤回任务");

                //完成任务 当前流程入参 撤销操作人的用户 和流程图接收参数key 例如：userList：id  ==> getVariables
                taskService.setAssignee(task.getId(), null);
                taskService.complete(task.getId(), actProcess.getVariables(), true);

                //恢复原方向
                flowNode.setOutgoingFlows(oriSequenceFlows);

                return true;
            }
        }

        return false;
    }
}
